package com.zqxq.lottery.api.utils;
import com.alibaba.fastjson.JSONObject;
import com.zqxq.common.constant.Result;
import com.zqxq.common.enums.CodeEnum;
import com.zqxq.common.utils.DateUtils;
import com.zqxq.common.utils.DispatcherUtils;
import com.zqxq.common.utils.StrUtils;
import com.zqxq.lottery.api.feign.LotteryServerFeignClient;
import com.zqxq.lottery.common.utils.FootBallBetUtils;
import com.zqxq.lottery.entity.bo.jczq.JczqWorldCupBO;
import com.zqxq.lottery.entity.constant.BasketBallRule;
import com.zqxq.lottery.entity.constant.FootBallRule;
import com.zqxq.lottery.entity.enums.LotteryIdEnum;
import com.zqxq.lottery.entity.o2o.order.UserOrderO2O;
import com.zqxq.lottery.entity.po.jczq.JczqMatchPO;
import com.zqxq.lottery.entity.po.order.UserOrderPO;
import com.zqxq.lottery.entity.po.sys.SysConfigPO;
import com.zqxq.lottery.entity.vo.esports.ESportsPlaywayVO;
import com.zqxq.lottery.entity.vo.jczq.JczqMatchVO;
import com.zqxq.lottery.entity.vo.jczq.JczqWorldCupVO;
import com.zqxq.lottery.entity.vo.order.UserOrderBetVO;
import com.zqxq.lottery.entity.vo.order.UserOrderVO;
import com.zqxq.lottery.entity.vo.sys.LotteryHnumVO;
import com.zqxq.lottery.entity.vo.user.UserInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author 苦智
 * @date 2018/4/11 12:12
 * @description 七星彩算法
 * @ClassName QXCLotteryUtils
 */
@Slf4j
public class LotteryValidateUtils {
    public static String[] allNums = {"0,1,2","3,4,5","6,7,8,9,10,11,12,13,14",
            "15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45",
            "46,47,48,49,50,51,52,53"};
    public static String[] allPlays = {"胜平负","让球胜平负","半全场","比分","总进球"};
    private LotteryServerFeignClient lotteryServerFeignClient;
    public LotteryValidateUtils(LotteryServerFeignClient lotteryServerFeignClient){
        this.lotteryServerFeignClient = lotteryServerFeignClient;
    }


    /**
     * @return boolean
     * @Author 苦智
     * @Description 订单校验(校验用户购票金额与后台数据是否一致)
     * @Date 13:55 2018/4/11
     * @Param [vo]
     **/
    public Result validateOrder(UserOrderVO vo) {
        if (StrUtils.isEmpty(vo.getUserId()) || StrUtils.isEmpty(vo.getLotteryId()) || StrUtils.isEmpty(vo.getPeriod()) || StrUtils.isEmpty(vo.getBetNum()) || StrUtils.isEmpty(vo.getBetTimes()) || StrUtils.isEmpty(vo.getPayAmount())) {
            return new Result(CodeEnum.FAIL_100002.getCode(),CodeEnum.FAIL_100002.getMsg());
        }
        Result<UserInfoVO> userInfoVOResult = lotteryServerFeignClient.getUserInfo(Long.valueOf(vo.getUserId()));
        UserInfoVO userInfoVO = userInfoVOResult.getData();
        String enabled = userInfoVO.getEnabled();
        if("1".equals(enabled)){
            return new Result(10000,"抱歉，您的账户已被禁用,不能进行敏感操作！");
        }
        /*Result<SysConfigPO> sysConfigPOResult = lotteryServerFeignClient.queryConfigValue("","FIRST_ORDER_PAYAMOUNT");
        String firstOrderPayAmount = "5";
        if(sysConfigPOResult!=null){
            firstOrderPayAmount = sysConfigPOResult.getData().getCval();
        }*/
        //判断用户是否绑定支付宝
        Result r = lotteryServerFeignClient.validateUserAlipay(vo.getUserId());
        if (!r.success())
            return r;


        //最多999倍
        if(Integer.parseInt(vo.getBetTimes())>999){
            log.error("投注倍数不能超过999倍！");
            return new Result(CodeEnum.FAIL_100002.getCode(),"投注倍数不能超过999倍！");
        }
        vo.setPayAmount(String.valueOf(new BigDecimal(vo.getPayAmount()).intValue()));
        UserOrderPO po = UserOrderO2O.toPO(vo);
        if(po.getPay_amount().compareTo(new BigDecimal(2))<0){
            return new Result(CodeEnum.FAIL_100002.getCode(),"投注金额最小2元起！");
        }
        String betJson = vo.getOrderBetJson();
        if (StrUtils.isEmpty(betJson)) {
            return new Result(CodeEnum.FAIL_100002.getCode(), "投注信息为空！");
        }
        List<UserOrderBetVO> orderBetList = JSONObject.parseArray(betJson, UserOrderBetVO.class);
        Long amount = 0L;
        Long lotteryId = DispatcherUtils.parseLong(vo.getLotteryId());
        Long lotteryTime = 0L;
        //足彩验证
        if(lotteryId.equals(LotteryIdEnum.JCZQ.getId())){
            if(orderBetList.size()>8){
                log.error("投注最大场次不能超过8场！");
                return new Result(CodeEnum.FAIL_100002.getCode(),"投注最大场次不能超过8场");
            }
            String[] betBunchs = vo.getBetBunch().split(",");
            String playTypeOne = orderBetList.get(0).getPlayType();
            for (String betBunch : betBunchs) {
                Integer betBunchNumStart = Integer.valueOf(betBunch.split("\\-")[0]);
                Integer betBunchNum = Integer.valueOf(betBunch.split("\\-")[1]);
                if (betBunchs.length > 1 && betBunchNum > 1) {
                    log.error("串法m串n：n大于1不能多选！");
                    return new Result(CodeEnum.FAIL_100002.getCode(), "串法m串n：n大于1不能多选！");
                }
                //竞足比分、半全场最多4关，总进球最多6关，胜平负、让球最多8关。
                //{1:'胜平负',2:'让球胜平负',3:'比分',4:'总进球',5:'半全场',6:'混合投注',7:'单关固定',8:'猜一场',9:'2选1'}
                if ("3".equals(playTypeOne) || "5".equals(playTypeOne)) {
                    if (betBunchNumStart > 4) {
                        log.error("比分、半全场最多4关！");
                        return new Result(CodeEnum.FAIL_100002.getCode(), "比分、半全场最多4关！");
                    }
                } else if ("4".equals(playTypeOne)) {
                    if (betBunchNumStart > 6) {
                        log.error("总进球最多6关");
                        return new Result(CodeEnum.FAIL_100002.getCode(), "总进球最多6关！");
                    }
                }
            }
            List<List<Integer>> betLists = new ArrayList();
            for (UserOrderBetVO bet : orderBetList) {
                String SelectNumbers = bet.getRedNum();  //选的号
                String field = bet.getPeriod();    //场次
                Result<JczqMatchVO> result = lotteryServerFeignClient.getJczqMatchById(field);
                JczqMatchVO jczqMatchVO = result.getData();
                Long closeTime = Long.valueOf(jczqMatchVO.getCloseTime());
                if (lotteryTime == 0L)
                    lotteryTime = closeTime;
                Long currentTime = System.currentTimeMillis();
                if (closeTime < currentTime) {
                    log.error("比赛已经开始，不能购买！");
                    return new Result(CodeEnum.FAIL_100002.getCode(), "比赛已经开始，不能购买！");
                }
                if (closeTime < lotteryTime) {
                    lotteryTime = closeTime;
                }
                StringBuffer blueNum = new StringBuffer();
                List<Integer> betList = new ArrayList();
                JSONObject betOddsObj = JSONObject.parseObject(jczqMatchVO.getOdds());
                for (String SelectNumber : SelectNumbers.split(",")) {
                    //判断该场赛事的所有玩法是否全部开售
                    if (checkOpenStatus(jczqMatchVO.getDetailStatus(), SelectNumber)) {
                        Integer[] betNums = getBetNums(SelectNumber);
                        return new Result(CodeEnum.FAIL_100002.getCode(), jczqMatchVO.getMatchField() + allPlays[Arrays.asList(betNums).indexOf(1)] + "未开售");
                    }
                    String playType = bet.getPlayType();
                    if ("1".equals(playType)) {
                        if (!Arrays.asList(FootBallRule.spfKey).contains(Integer.valueOf(SelectNumber))) {
                            log.error("胜平负投注号码【{}】区间错误！【{}-{}】", SelectNumber, FootBallRule.spfKey[0], FootBallRule.spfKey[FootBallRule.spfKey.length - 1]);
                            return new Result(CodeEnum.FAIL_100002.getCode(), "胜平负投注号码区间错误！");
                        }
                    } else if ("2".equals(playType)) {
                        if (!Arrays.asList(FootBallRule.rqspfKey).contains(Integer.valueOf(SelectNumber))) {
                            log.error("让球胜平负投注号码【{}】区间错误！【{}-{}】", SelectNumber, FootBallRule.rqspfKey[0], FootBallRule.rqspfKey[FootBallRule.rqspfKey.length - 1]);
                            return new Result(CodeEnum.FAIL_100002.getCode(), "让球胜平负投注号码区间错误！");
                        }
                    } else if ("3".equals(playType)) {
                        if (!Arrays.asList(FootBallRule.bfKey).contains(Integer.valueOf(SelectNumber))) {
                            log.error("比分投注号码【{}】区间错误！【{}-{}】", SelectNumber, FootBallRule.bfKey[0], FootBallRule.bfKey[FootBallRule.bfKey.length - 1]);
                            return new Result(CodeEnum.FAIL_100002.getCode(), "比分投注号码区间错误！");
                        }
                    } else if ("4".equals(playType)) {
                        if (!Arrays.asList(FootBallRule.zjqKey).contains(Integer.valueOf(SelectNumber))) {
                            log.error("总进球投注号码【{}】区间错误！【{}-{}】", SelectNumber, FootBallRule.zjqKey[0], FootBallRule.zjqKey[FootBallRule.zjqKey.length - 1]);
                            return new Result(CodeEnum.FAIL_100002.getCode(), "总进球投注号码区间错误！");
                        }
                    } else if ("5".equals(playType)) {
                        if (!Arrays.asList(FootBallRule.bqcKey).contains(Integer.valueOf(SelectNumber))) {
                            log.error("半全场投注号码【{}】区间错误！【{}-{}】", SelectNumber, FootBallRule.bqcKey[0], FootBallRule.bqcKey[FootBallRule.bqcKey.length - 1]);
                            return new Result(CodeEnum.FAIL_100002.getCode(), "半全场投注号码区间错误！");
                        }
                    } else if ("7".equals(playType)) {
                        //单关固定玩法校验 field场次 SelectNumbers选号
                        if (!validateDg(field, SelectNumber)) {
                            Integer[] betNums = getBetNums(SelectNumber);
                            String tag = "";
                            for (int i = 0; i < betNums.length; i++) {
                                if (betNums[i] == 1) {
                                    tag = allPlays[i];
                                }
                            }
                            return new Result(CodeEnum.FAIL_100002.getCode(), jczqMatchVO.getMatchField() + tag + "不支持单关");
                        }
                    }

                    blueNum.append(betOddsObj.get(SelectNumber) + ",");
                    betList.add(Integer.valueOf(SelectNumber));
                }
                betLists.add(betList);
                bet.setBlueNum(blueNum.deleteCharAt(blueNum.length() - 1).toString());
            }
            Integer[][] arr = new Integer[betLists.size()][];
            for (int i = 0; i < betLists.size(); i++) {
                List<Integer> bl = betLists.get(i);
                arr[i] = bl.toArray(new Integer[0]);
            }
            if (vo.getIsPublishFollow() != null && "0".equals(vo.getIsPublishFollow())) {
                //推单验证
                Result result = validatePushOrder(vo, orderBetList);
                if (CodeEnum.FAIL_100002.getCode() == result.getCode()) {
                    return result;
                }
            }
            if(!StringUtils.isEmpty(vo.getIsBonusOptimize()) && "0".equals(vo.getIsBonusOptimize())){
                return validateBonusOptimizeOrder(vo,orderBetList);
            }
            Integer betNum = FootBallBetUtils.betNum(vo.getBetBunch().split(","), arr);
            if (betNum != Integer.parseInt(vo.getBetNum())) {    //注数验证
                log.error("{}-{}注数不匹配！", vo.getBetNum(), betNum);
                return new Result(CodeEnum.FAIL_100002.getCode(), "注数不匹配！");
            }

            amount = betNum * 2  * DispatcherUtils.parseLong(vo.getBetTimes());

        }else if(lotteryId.equals(LotteryIdEnum.JCZQ_JJ.getId())){
            return validateOrder_210(vo,po,orderBetList);
        }else if(lotteryId.equals(LotteryIdEnum.DJ.getId())){
            return validateOrder_10(vo,po,orderBetList);
        }else if(lotteryId.equals(LotteryIdEnum.JCLQ.getId())){
            return validateOrder_24(vo,po,orderBetList);
        }else {
            //数字竞猜
            for (UserOrderBetVO bet : orderBetList) {
                long betNum = 0;
                String chooseNum = bet.getRedNum();
                if (lotteryId == LotteryIdEnum.SSQ.getId() || lotteryId == LotteryIdEnum.DLT.getId())
                    chooseNum = bet.getRedNum() + "|" + bet.getBlueNum();
                betNum = betNum(lotteryId, DispatcherUtils.parseInteger(bet.getPlayType()), chooseNum);
                //每组投注注数不能小于0
                if (betNum <= 0){
                    log.error("每组投注注数不能小于0！");
                    return new Result(CodeEnum.FAIL_100002.getCode(),"每组投注注数不能小于0！");
                }
                bet.setBetNum(betNum + "");
                bet.setBetTimes(vo.getBetTimes());
                amount += betNum * po.getBet_times()* 2*100; //计算投注金额
            }
            Result<LotteryHnumVO> lotteryHnumVOResult = lotteryServerFeignClient.getLotteryHnumByPeriod(Long.valueOf(vo.getPeriod()));
            LotteryHnumVO lotteryHnumVO = lotteryHnumVOResult.getData();
            if(lotteryHnumVO!=null){
                lotteryTime = Long.valueOf(DateUtils.strToDate(lotteryHnumVO.getCloseTime()).getTime());
            }
        }
        Date lt = new Date(lotteryTime);
        vo.setLotteryTime(DateUtils.dateToStr(lt));
        if (!po.getPay_amount().equals(new BigDecimal(amount))) {
            log.error("{}-{} 投注金额不匹配！",po.getPay_amount(),amount);
            return new Result(CodeEnum.FAIL_100002.getCode(),"投注金额不匹配！");
        }
        vo.setOrderBetList(orderBetList);
        return new Result();
    }

    private Result validateBonusOptimizeOrder(UserOrderVO vo,List<UserOrderBetVO> orderBetList){
        String [] betBunchs = vo.getBetBunch().split(",");
        for (String betBunch : betBunchs){
            Integer betBunchNum = Integer.valueOf(betBunch.split("\\-")[1]);
            if (betBunchNum>1){
                return new Result(CodeEnum.FAIL_100002.getCode(),"奖金优化只支持m串1！");
            }
        }
        vo.setOrderBetList(orderBetList);
        return new Result();
    }

    public static boolean checkOpenStatus(String detailStatus,String selectNumber){
        boolean flag = false;
        Integer[] betNums = getBetNums(selectNumber);
        int i = Arrays.asList(betNums).indexOf(1); //所选玩法对应的索引
        String s = String.valueOf(detailStatus.replace(",","").charAt(i)); //所选玩法开售状态
        if (s.equals("1")){
            flag=true;
        }
        return flag;
    }

    public static boolean checkOpenStatus24(String detailStatus,String selectNumber){
        boolean flag = false;
        Integer[] betNums = getBetNums24(selectNumber);
        int i = Arrays.asList(betNums).indexOf(1); //所选玩法对应的索引
        String s = String.valueOf(detailStatus.replace(",","").charAt(i)); //所选玩法开售状态
        if (s.equals("1")){
            flag=true;
        }
        return flag;
    }

    public Result validatePushOrder(UserOrderVO vo,List<UserOrderBetVO> orderBetList) {
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        String betBunchs = vo.getBetBunch(); //串投方式
        BigDecimal payAmount = new BigDecimal(vo.getPayAmount());
        BigDecimal min = BigDecimal.ZERO;
        String betStr = betBunchs+"#";
        //1.玩法支持：单关、2串1胜平负、让球胜平负、比分、半全场，进球数
        try {
            Result expertResult = lotteryServerFeignClient.getExpertInfo(Long.valueOf(vo.getUserId()));
            if(expertResult.getData()==null){
                return new Result(CodeEnum.FAIL_100002.getCode(),"抱歉，只有专家才能推单！");
            }else{
                BigDecimal commissionRate = new BigDecimal(vo.getCommissionRate());
                Map<String,Object> expertInfoMap = (Map<String, Object>) expertResult.getData();
                BigDecimal max = new BigDecimal(String.valueOf(expertInfoMap.get("max")));
                if(commissionRate.compareTo(max)==1){
                    return new Result(CodeEnum.FAIL_100002.getCode(),"抱歉，您输入的佣金比例和您的专家等级不符！");
                }
            }

            Result<SysConfigPO> sysConfigPOResult = lotteryServerFeignClient.queryConfigValue("","PUSH_ORDER_SWITCH");
            SysConfigPO sysConfigPO = sysConfigPOResult.getData();
            if(orderBetList!=null && orderBetList.size()>0){
                List<Double[]> list = new ArrayList();
                for (UserOrderBetVO bet : orderBetList) {
                    String redNum = bet.getRedNum();
                    String[] redNums = bet.getRedNum().split("\\,");
                    Result<JczqMatchVO> result = lotteryServerFeignClient.getJczqMatchById(bet.getPeriod());
                    betStr+=bet.getPeriod()+":"+sortRemNum(bet.getRedNum())+"|";
                    JczqMatchVO jczqMatchVO = result.getData();
                    //下注的比赛不能超过48小时
                    Long closeTime = Long.valueOf(jczqMatchVO.getCloseTime());
                    Calendar c = Calendar.getInstance();
                    c.setTime(new Date());
                    c.add(Calendar.DAY_OF_MONTH, 2);
                    Date afterTomorrow = c.getTime();
                    String dateStr = f.format(afterTomorrow);
                    Date date = f.parse(dateStr);
                    Long afterTomorrowTime = date.getTime();
                    if(closeTime>=afterTomorrowTime){
                        return new Result(CodeEnum.FAIL_100002.getCode(),"推单下注的比赛不能超过48小时！");
                    }

                    Map<String,String> oddsMap = new HashMap();
                    Integer playType1Count = 0; //胜平负选择数
                    Integer playType2Count = 0; //让球胜平负选择数
                    Integer playType3Count = 0; //比分选择数
                    Integer playType4Count = 0; //总进球选择数
                    Integer playType5Count = 0; //半全场选择数
                    for (int i=0;i<redNums.length;i++) {
                        if ("0".equals(redNums[i]) || "1".equals(redNums[i]) || "2".equals(redNums[i])) {
                            playType1Count++;
                        } else if ("3".equals(redNums[i]) || "4".equals(redNums[i]) || "5".equals(redNums[i])) {
                            playType2Count++;
                        } else if ("15".equals(redNums[i]) || "16".equals(redNums[i]) || "17".equals(redNums[i]) || "18".equals(redNums[i]) || "19".equals(redNums[i]) || "20".equals(redNums[i]) || "21".equals(redNums[i]) || "22".equals(redNums[i]) || "23".equals(redNums[i]) || "24".equals(redNums[i]) || "25".equals(redNums[i]) || "26".equals(redNums[i]) || "27".equals(redNums[i]) || "28".equals(redNums[i]) || "29".equals(redNums[i]) || "30".equals(redNums[i]) || "31".equals(redNums[i]) || "32".equals(redNums[i]) || "33".equals(redNums[i]) || "34".equals(redNums[i]) || "35".equals(redNums[i]) || "36".equals(redNums[i]) || "37".equals(redNums[i]) || "38".equals(redNums[i]) || "39".equals(redNums[i]) || "40".equals(redNums[i]) || "41".equals(redNums[i]) || "42".equals(redNums[i]) || "43".equals(redNums[i]) || "44".equals(redNums[i]) || "45".equals(redNums[i])) {
                            playType3Count++;
                        } else if ("46".equals(redNums[i]) || "47".equals(redNums[i]) || "48".equals(redNums[i]) || "49".equals(redNums[i]) || "50".equals(redNums[i]) || "51".equals(redNums[i]) || "52".equals(redNums[i]) || "53".equals(redNums[i])) {
                            playType4Count++;
                        } else if ("6".equals(redNums[i]) || "7".equals(redNums[i]) || "8".equals(redNums[i]) || "9".equals(redNums[i]) || "10".equals(redNums[i]) || "11".equals(redNums[i]) || "12".equals(redNums[i]) || "13".equals(redNums[i]) || "14".equals(redNums[i])) {
                            playType5Count++;
                        }
                        oddsMap.put(redNums[i],bet.getBlueNum().split("\\,")[i]);
                        //1、胜平负、让球胜平负单关玩法单场最多3选2
                        //2、进球数玩法，单场最多不超过4个方案
                        //3、半全场玩法，单场最多不能超过5个方案
                        //4、比分玩法，单场最多不能超过8个方案
                        //5、混合投注玩法，最多2串1，且单场单玩法满足上面条件
                        if(sysConfigPO!=null && "1".equals(sysConfigPO.getCval())) {
                            if (playType1Count > 2 || playType2Count > 2) {
                                return new Result(CodeEnum.FAIL_100002.getCode(), "推单胜平负、让球胜平负单场最多3选2！");
                            }
                            if (playType3Count > 8) {
                                return new Result(CodeEnum.FAIL_100002.getCode(), "推单比分玩法，单场最多不能超过8个方案！");
                            }
                            if (playType4Count > 4) {
                                return new Result(CodeEnum.FAIL_100002.getCode(), "推单进球数玩法，单场最多不超过4个方案！");
                            }
                            if (playType5Count > 5) {
                                return new Result(CodeEnum.FAIL_100002.getCode(), "推单半全场玩法，单场最多不能超过5个方案！");
                            }
                        }
                    }
                    if(!ObjectUtils.isEmpty(jczqMatchVO)){
                        Double[] m1 = FootBallBetUtils.getMinMaxOdds(redNum,oddsMap);
                        list.add(m1);
                    }
                }
                Double minBonus = FootBallBetUtils.betMinVal(vo.getBetBunch().split(","), list);
                min = new BigDecimal(minBonus).multiply(new BigDecimal(vo.getBetTimes())).setScale(2,BigDecimal.ROUND_HALF_UP);
            }
            if(sysConfigPO!=null && "1".equals(sysConfigPO.getCval())) {
                for (String betBunch : betBunchs.split(",")) {
                    Integer bunch = Integer.valueOf(betBunch.split("-")[0]);
                    if (bunch > 2) {
                        return new Result(CodeEnum.FAIL_100002.getCode(), "推单只支持单关、2串1！");
                    }
                    //3.2串1最低中奖金额不低于本金50%
                    if (bunch == 2) {
                        if (min.compareTo(payAmount.multiply(new BigDecimal(0.5))) < 0) {
                            return new Result(CodeEnum.FAIL_100002.getCode(), "推单2串1最低中奖金额不低于本金50%！");
                        }
                    }
                }
            }
            Integer heelMultiple = Integer.valueOf(vo.getHeelMultiple());
            if(heelMultiple==0){
                return new Result(CodeEnum.FAIL_100002.getCode(),"推单起跟倍数不能为0！");
            }


            //每人每日推单不超过3单
            /*Result result = lotteryServerFeignClient.getUserTodayPushOrder(vo.getUserId());
            Integer count = (Integer) result.getData();
            if(count>=3){
                return new Result(CodeEnum.FAIL_100002.getCode(),"每人每日推单不超过3单！");
            }*/
            //2.单笔订单投注金额大于等于100元
            /*Result<SysConfigPO> sysConfigOrderMoneyResult = lotteryServerFeignClient.queryConfigValue("","PUSH_ORDER_ORDER_MIN_AMOUNT");
            SysConfigPO sysConfigOrderMoney = sysConfigOrderMoneyResult.getData();

            if(payAmount.compareTo(new BigDecimal(sysConfigOrderMoney.getCval()))<0){
                return new Result(CodeEnum.FAIL_100002.getCode(),"发布推单金额不能低于"+sysConfigOrderMoney.getCval()+"元！");
            }*/
            //相同方案内容只可推荐1次
            /*Result<List<UserOrderVO>> resultList = lotteryServerFeignClient.getUserTwoDayPushOrder(vo.getUserId());    //查询近2天的订单
            if(resultList.getData()!=null){
                List<UserOrderVO> userOrderVOList = (List<UserOrderVO>) resultList.getData();
                for(UserOrderVO userOrderVO : userOrderVOList){
                    String pushOrderBetStr = userOrderVO.getBetBunch()+"#";
                    List<UserOrderBetVO> userOrderBetVOList = userOrderVO.getOrderBetList();
                    for(UserOrderBetVO userOrderBetVO : userOrderBetVOList){
                        pushOrderBetStr += userOrderBetVO.getPeriod()+":"+sortRemNum(userOrderBetVO.getRedNum())+"|";
                    }
                    if(pushOrderBetStr.equals(betStr)){
                        return new Result(CodeEnum.FAIL_100002.getCode(),"相同方案内容只可推荐1次！");
                    }
                }
            }*/
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new Result();
    }
    public String sortRemNum(String redNums){
        String returnRedNum = "";
        List<Integer> redNumList = new ArrayList();
        for(String redNum : redNums.split(",")){
            redNumList.add(Integer.valueOf(redNum));
        }
        Collections.sort(redNumList);
        for(Integer num : redNumList){
            returnRedNum += num+",";
        }
        return returnRedNum.substring(0,returnRedNum.length()-1);
    }
    /**
     * @Author 苦智
     * @Description 判断选号是否支持单关
     * @Date 10:40 2018/8/1
     * @Param [code, selectNumbers]
     * @return boolean
     **/
    public boolean validateDg(String code,String num){
        boolean flag = true;
        if (StrUtils.isEmpty(num))
            return false;
        Result r = lotteryServerFeignClient.getJczqMatchByCode(code);
        if (r.success()){
            JczqMatchPO jczqMatchPO = JSONObject.parseObject(JSONObject.toJSONString(r.getData()), JczqMatchPO.class);
            String pass_status = jczqMatchPO.getPass_status();
            if (StrUtils.isNotEmpty(pass_status)){
                String[] passStatus = pass_status.split(",");
                flag = validatePlayType(passStatus, num);
            }
        }
        return flag;
    }

    public boolean validateDg24(String code,String num){
        boolean flag = true;
        if (StrUtils.isEmpty(num))
            return false;
        Result r = lotteryServerFeignClient.getJczqMatchByCode(code);
        if (r.success()){
            JczqMatchPO jczqMatchPO = JSONObject.parseObject(JSONObject.toJSONString(r.getData()), JczqMatchPO.class);
            String pass_status = jczqMatchPO.getPass_status();
            if (StrUtils.isNotEmpty(pass_status)){
                String[] passStatus = pass_status.split(",");
                flag = validatePlayType24(passStatus, num);
            }
        }
        return flag;
    }

    private boolean validatePlayType24(String[] passStatus, String num) {
        Integer[] chooseNum = getBetNums24(num);
        for (int i = 0;i<passStatus.length;i++) {
            int s = Integer.parseInt(passStatus[i]);
            if (chooseNum[i] == 1){
                if (s != chooseNum[i])
                    return false;
            }
        }
        return true;
    }

    private boolean validatePlayType(String[] passStatus, String num) {
        Integer[] chooseNum = getBetNums(num);
        for (int i = 0;i<passStatus.length;i++) {
            int s = Integer.parseInt(passStatus[i]);
            if (chooseNum[i] == 1){
                if (s != chooseNum[i])
                    return false;
            }
        }
        return true;
    }

    private static Integer[] getBetNums(String num) {
        Integer[] chooseNum = {0,0,0,0,0};
        for (int i=0;i<allNums.length;i++) {
            for (String n: allNums[i].split(",")){
                if (n.equals(num))
                    chooseNum[i] = 1;
            }
        }
        return chooseNum;
    }

    private static Integer[] getBetNums24(String num) {
        Integer[] chooseNum = {0,0,0,0};
        for (int i=0;i<allNums.length;i++) {
            for (String n: allNums[i].split(",")){
                if (n.equals(num))
                    chooseNum[i] = 1;
            }
        }
        return chooseNum;
    }


    //冠军|冠亚军 校验
    private Result validateOrder_210(UserOrderVO vo,UserOrderPO po,List<UserOrderBetVO> orderBetList){
        if(!"1-1".equals(vo.getBetBunch()) || orderBetList.size()!=1)
            return new Result(CodeEnum.FAIL_100002.getCode(),"参数错误！");
        UserOrderBetVO betVO = orderBetList.get(0);
        String[] betNums = betVO.getRedNum().split(",");
        Long amount = 2L * po.getBet_times() * betNums.length;
        if (!po.getPay_amount().equals(new BigDecimal(amount))) {
            log.error("{}-{} 投注金额不匹配！",po.getPay_amount(),amount);
            return new Result(CodeEnum.FAIL_100002.getCode(),"投注金额不匹配！");
        }
        JczqWorldCupBO search = new JczqWorldCupBO();
        search.setStatus(0);
        search.setPeriod(vo.getPeriod());
        search.setType(Integer.parseInt(orderBetList.get(0).getPlayType()));
        Result<Map<String,JczqWorldCupVO>> cupRs = lotteryServerFeignClient.queryWorldCupMap(search);
        Map<String,JczqWorldCupVO> map = cupRs.getData();
        String blueNum = "";
        for(String betNum : betNums){
            String key = betVO.getPeriod()+"_"+betVO.getPlayType()+"_"+betNum;
            JczqWorldCupVO cup = map.get(key);
            if(null == cup)
                return new Result(CodeEnum.FAIL_100002.getCode(),"投注信息错误，场次已关闭！");
            blueNum += ","+cup.getOdds();
        }
        blueNum = blueNum.length()>0?blueNum.substring(1):"";
        betVO.setBlueNum(blueNum);
        betVO.setBetNum(betNums.length+"");
        vo.setOrderBetList(orderBetList);
        return new Result();
    }

    private Result validateOrder_10(UserOrderVO vo,UserOrderPO po,List<UserOrderBetVO> orderBetList){
        if(!"1-1".equals(vo.getBetBunch()) || orderBetList.size()!=1)
            return new Result(CodeEnum.FAIL_100002.getCode(),"参数错误！");
        Integer amount = po.getPay_amount().intValue() * po.getBet_times() * po.getBet_num();
        if (po.getPay_amount().compareTo(new BigDecimal(amount))!=0) {
            log.error("{}-{} 投注金额不匹配！",po.getPay_amount(),amount);
            return new Result(CodeEnum.FAIL_100002.getCode(),"投注金额不匹配！");
        }
        if(po.getPay_amount().compareTo(new BigDecimal(100000))==1){
            return new Result(CodeEnum.FAIL_100002.getCode(),"单笔订单最多可投10万趣豆！");
        }
        Long lotteryTime = 0L;
        String userId = vo.getUserId();
        for(UserOrderBetVO userOrderBetVO : orderBetList){
            String period = userOrderBetVO.getPeriod();
            String playType = userOrderBetVO.getPlayType();
            String redNum = userOrderBetVO.getRedNum();
            //一场比赛的一场玩法只能选择一方
            Result<UserOrderBetVO> result1 = lotteryServerFeignClient.getMatchPlayTypeChoice(userId,period,playType);
            if(result1.getData()!=null){
                if(!result1.getData().getRedNum().equals(redNum)) {
                    return new Result(CodeEnum.FAIL_100002.getCode(), "一场比赛中同一玩法只能选择一方！");
                }
            }
            Result<ESportsPlaywayVO> eSportsPlaywayVOResult = lotteryServerFeignClient.queryESportsPlaytype(period,playType);
            ESportsPlaywayVO eSportsPlaywayVO = eSportsPlaywayVOResult.getData();
            Long closeTime = Long.valueOf(eSportsPlaywayVO.getCloseTime());
            if(lotteryTime==0L)
                lotteryTime = closeTime;
            Long currentTime = System.currentTimeMillis();
            if(closeTime<currentTime){
                return new Result(CodeEnum.FAIL_100002.getCode(),"该场比赛该玩法不能预测！");
            }
            if(closeTime<lotteryTime){
                lotteryTime = closeTime;
            }
            if("1".equals(eSportsPlaywayVO.getBetStatus())){
                return new Result(CodeEnum.FAIL_100002.getCode(),"该场比赛该玩法不能预测！");
            }
            Map<String,Object> playsMap = JSONObject.parseObject(eSportsPlaywayVO.getPlayOdds(),Map.class);
            Map<String,Object> playMap = JSONObject.parseObject(JSONObject.toJSONString(playsMap.get(redNum)),Map.class);
            String betOdds = (String) playMap.get("partOdds");
            userOrderBetVO.setBlueNum(betOdds);
        }
        Date lt = new Date(lotteryTime);
        vo.setLotteryTime(DateUtils.dateToStr(lt));
        vo.setOrderBetList(orderBetList);
        return new Result();
    }

    private Result validateOrder_24(UserOrderVO vo,UserOrderPO po,List<UserOrderBetVO> orderBetList){
        Long amount = 0L;
        Long lotteryTime = 0L;
        if(orderBetList.size()>8){
            log.error("投注最大场次不能超过8场！");
            return new Result(CodeEnum.FAIL_100002.getCode(),"投注最大场次不能超过8场");
        }
        String [] betBunchs = vo.getBetBunch().split(",");
        String playTypeOne = orderBetList.get(0).getPlayType();
        for (String betBunch : betBunchs){
            Integer betBunchNumStart = Integer.valueOf(betBunch.split("\\-")[0]);
            Integer betBunchNum = Integer.valueOf(betBunch.split("\\-")[1]);
            if (betBunchs.length>1 && betBunchNum>1){
                log.error("串法m串n：n大于1不能多选！");
                return new Result(CodeEnum.FAIL_100002.getCode(),"串法m串n：n大于1不能多选！");
            }
            //竞篮胜分差最多4关。
            //1：胜负；2：让分胜负；3：胜分差；4：大小分；5：混合过关；6：单关；
            if ("3".equals(playTypeOne)) {
                if (betBunchNumStart > 4) {
                    return new Result(CodeEnum.FAIL_100002.getCode(), "胜分差最多4关！");
                }
            }
        }
        List<List<Integer>> betLists = new ArrayList();
        for (UserOrderBetVO bet : orderBetList) {
            String SelectNumbers = bet.getRedNum();  //选的号
            String field = bet.getPeriod();    //场次
            Result<JczqMatchVO> result = lotteryServerFeignClient.getJczqMatchById(field);
            JczqMatchVO jczqMatchVO = result.getData();
            Long closeTime = Long.valueOf(jczqMatchVO.getCloseTime());
            if(lotteryTime==0L)
                lotteryTime = closeTime;
            Long currentTime = System.currentTimeMillis();
            if(closeTime<currentTime){
                log.error("比赛已经开始，不能购买！");
                return new Result(CodeEnum.FAIL_100002.getCode(),"比赛已经开始，不能购买！");
            }
            if(closeTime<lotteryTime){
                lotteryTime = closeTime;
            }
            StringBuffer blueNum = new StringBuffer();
            List<Integer> betList = new ArrayList();
            JSONObject betOddsObj = JSONObject.parseObject(jczqMatchVO.getOdds());
            for(String SelectNumber : SelectNumbers.split(",")){
                //判断该场赛事的所有玩法是否全部开售
                if (checkOpenStatus24(jczqMatchVO.getDetailStatus(),SelectNumber)){
                    Integer[] betNums = getBetNums24(SelectNumber);
                    return new Result(CodeEnum.FAIL_100002.getCode(), jczqMatchVO.getMatchField()+allPlays[Arrays.asList(betNums).indexOf(1)]+"未开售");
                }
                String playType =bet.getPlayType();
                if ("1".equals(playType)) {
                    if(!Arrays.asList(BasketBallRule.sfKey).contains(Integer.valueOf(SelectNumber))){
                        return new Result(CodeEnum.FAIL_100002.getCode(),"胜负投注号码区间错误！");
                    }
                }else if("2".equals(playType)){
                    if(!Arrays.asList(BasketBallRule.rfsfKey).contains(Integer.valueOf(SelectNumber))){
                        return new Result(CodeEnum.FAIL_100002.getCode(),"让分胜负投注号码区间错误！");
                    }
                }else if("3".equals(playType)){
                    if(!Arrays.asList(BasketBallRule.sfcKey).contains(Integer.valueOf(SelectNumber))){
                        return new Result(CodeEnum.FAIL_100002.getCode(),"胜分差投注号码区间错误！");
                    }
                }else if("4".equals(playType)){
                    if(!Arrays.asList(BasketBallRule.dxfKey).contains(Integer.valueOf(SelectNumber))){
                        return new Result(CodeEnum.FAIL_100002.getCode(),"大小分投注号码区间错误！");
                    }
                }else if("7".equals(playType)){
                    //单关固定玩法校验 field场次 SelectNumbers选号
                    if (!validateDg24(field,SelectNumber)) {
                        Integer[] betNums = getBetNums24(SelectNumber);
                        String tag = "";
                        for (int i = 0;i<betNums.length;i++ ) {
                            if (betNums[i] == 1){
                                tag =  allPlays[i];
                            }
                        }
                        return new Result(CodeEnum.FAIL_100002.getCode(), jczqMatchVO.getMatchField()+tag+"不支持单关");
                    }
                }
                blueNum.append(betOddsObj.get(SelectNumber)+",");
                betList.add(Integer.valueOf(SelectNumber));
            }
            betLists.add(betList);
            bet.setBlueNum(blueNum.deleteCharAt(blueNum.length()-1).toString());
        }
        Integer[][] arr = new Integer[betLists.size()][];
        for(int i=0;i<betLists.size();i++){
            List<Integer> bl = betLists.get(i);
            arr[i] = bl.toArray(new Integer[0]);
        }
        Date lt = new Date(lotteryTime);
        vo.setLotteryTime(DateUtils.dateToStr(lt));
        if(!StringUtils.isEmpty(vo.getIsBonusOptimize()) && "0".equals(vo.getIsBonusOptimize())){
            return validateBonusOptimizeOrder(vo,orderBetList);
        }
        Integer betNum = FootBallBetUtils.betNum(vo.getBetBunch().split(","),arr);
        amount = betNum*2*100*DispatcherUtils.parseLong(vo.getBetTimes());
        if (betNum!=Integer.parseInt(vo.getBetNum())){    //注数验证
            log.error("{}-{}注数不匹配！",vo.getBetNum(),betNum);
            return new Result(CodeEnum.FAIL_100002.getCode(),"注数不匹配！");
        }
        if (!po.getPay_amount().equals(new BigDecimal(amount))) {
            log.error("{}-{} 投注金额不匹配！",po.getPay_amount(),amount);
            return new Result(CodeEnum.FAIL_100002.getCode(),"投注金额不匹配！");
        }
        vo.setOrderBetList(orderBetList);
        return new Result();
    }


    //投注计算：选球格式-- [胆],拖|[胆],拖|拖
    //胆：固定选球；拖：可变选球
    private static long betNum(Long lotteryId, Integer playType, String chooseNum) {
        if (StrUtils.isEmpty(chooseNum))
            return 0;
        long betNum;
        if (null == playType)
            playType = 1;
        String[] chooseNums = chooseNum.split("\\|");
        LotteryIdEnum idEnum = LotteryIdEnum.getEnumById(lotteryId);
        switch (idEnum) {
            case SSQ:
                if (chooseNums.length != 2)
                    return 0;
                switch (playType) {
                    case 1:
                        betNum = combine(chooseNums[0].split(",").length, 6) * combine(chooseNums[1].split(",").length, 1);
                        break;
                    case 2:
                        if(chooseNums[0].indexOf(")")<1)
                            return 0;
                        int danLen = chooseNums[0].substring(1, chooseNums[0].indexOf(")")).split(",").length;
                        int tuoLen = chooseNums[0].substring(chooseNums[0].indexOf(")") + 2).split(",").length;
                        betNum = combine(tuoLen, 6 - danLen) * combine(chooseNums[1].split(",").length, 1);
                        break;
                    default:
                        betNum = 0;
                }
                break;
            case DLT:
                if (chooseNums.length != 2)
                    return 0;
                switch (playType) {
                    case 1:
                        betNum = combine(chooseNums[0].split(",").length, 5) * combine(chooseNums[1].split(",").length, 2);
                        break;
                    case 2:
                        if(chooseNums[0].indexOf(")")<1)
                            return 0;
                        int frontDanLen = chooseNums[0].substring(1, chooseNums[0].indexOf(")")).split(",").length;
                        int frontTuoLen = chooseNums[0].substring(chooseNums[0].indexOf(")") + 2).split(",").length;
                        if (chooseNums[1].contains(")")) {
                            //后区胆拖
                            int afterTuoLen = chooseNums[1].substring(chooseNums[1].indexOf(")") + 2).split(",").length;
                            betNum = combine(frontTuoLen, 5 - frontDanLen) * combine(afterTuoLen, 1);
                        } else {
                            betNum = combine(frontTuoLen, 5 - frontDanLen) * combine(chooseNums[1].split(",").length, 2);
                        }
                        break;
                    default:
                        betNum = 0;
                }
                break;
            case FC:
            case PL:
                switch (playType) {
                    case 1:
                        if (chooseNums.length != 3)
                            return 0;
                        betNum = chooseNums[0].split(",").length * chooseNums[1].split(",").length * chooseNums[2].split(",").length;
                        break;
                    case 2:
                        if (chooseNums.length != 2)
                            return 0;
                        betNum = 1;
                        break;
                    case 3:
                        if (chooseNums.length != 1)
                            return 0;
                        betNum = combine(chooseNums[0].split(",").length, 2) * 2;
                        break;
                    case 4:
                        if (chooseNums.length != 1)
                            return 0;
                        betNum = combine(chooseNums[0].split(",").length, 3);
                        break;
                    default:
                        betNum = 0;
                }
                break;
            case QXC:
                if (chooseNums.length != 7)
                    return 0;
                betNum = chooseNums[0].split(",").length * chooseNums[1].split(",").length
                        * chooseNums[2].split(",").length * chooseNums[3].split(",").length
                        * chooseNums[4].split(",").length * chooseNums[5].split(",").length
                        * chooseNums[6].split(",").length;
                break;
            case JCZQ:
                betNum = 0;
                break;
            default:
                betNum = 0;

        }
        return betNum;
    }




    // 组合(C 下标m,上标n)
    private static long combine(int m, int n) {
        if (m < n || n < 0) {
            return 0L;
        }
        return factorial(m, m - n + 1) / factorial(n, 1);
    }

    // 阶乘
    private static long factorial(long max, long min) {
        if (max >= min && max > 1) {
            return max * factorial(max - 1, min);
        } else {
            return 1L;
        }
    }

    //排列
    private static long permutation(long max, long min) {
        if (max >= min && min > 0) {
            return max * permutation(max - 1, min - 1);
        } else {
            return 1L;
        }
    }

    public static void main(String[] args) {
//        boolean b = checkOpenStatus("1,1,1,0,0", "6");
//        System.out.println(b);
        Date date = DateUtils.strToDate("2018-11-30 23:32:00");
//        Long aLong = Long.valueOf("2018-11-30 09:22:00");
        long time = date.getTime();
        long l = System.currentTimeMillis();
        long time1 = new Date().getTime();
        System.out.println(time-time1);
        System.out.println(l-time1);
    }
}
